//
//  UIViewExtension.swift
//  SwiftExtensionDemo
//
//  Created by 腾億 on 2017/11/30.
//  Copyright © 2017年 tml. All rights reserved.
//
#if os(iOS) || os(tvOS)
import Foundation
import UIKit
//MARK: 自定义UIView初始化器
extension UIView {
    //便利构造函数，根据宽度，高度和底座坐标定义视图
    public convenience init(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
        self.init(frame: CGRect(x: x, y: y, width: width, height: height))
    }
    //填充周围视图
    public convenience init(superView: UIView, padding: CGFloat) {
        self.init(frame: CGRect(x: superView.x + padding, y: superView.y + padding, width: superView.width - padding*2, height: superView.height - padding*2))
    }
    
    //复制superview的大小
    public convenience init(superView: UIView) {
        self.init(frame: CGRect(origin: CGPoint.zero, size: superView.size))
    }
}

//MARK: Frame 扩展
extension UIView {
    //添加多个子视图
    public func addSubviews(_ view: [UIView]) {
        view.forEach { [weak self] eachView in
            self?.addSubview(eachView)
        }
    }
    
    //调整此视图的大小，使其适合最大的子视图
    public func resizeToFitSubviews() {
        var width: CGFloat = 0
        var height: CGFloat = 0
        for someView in self.subviews {
            let aView = someView
            let newWidth = aView.x + aView.width
            let newHeight = aView.y + aView.height
            width = max(width, newWidth)
            height = max(height, newHeight)
        }
        frame = CGRect(x: x, y: y, width: width, height: height)
    }
    
    public func resizeToFitSubviews(_ tagsToIgnore: [Int]) {
        var width: CGFloat = 0
        var height: CGFloat = 0
        for someView in self.subviews {
            let aView = someView
            if !tagsToIgnore.contains(someView.tag) {
                let newWidth = aView.x + aView.width
                let newHeight = aView.y + aView.height
                width = max(width, newWidth)
                height = max(height, newHeight)
            }
        }
        frame = CGRect(x: x, y: y, width: width, height: height)
    }
    
    //调整这个视图，以适应其宽度
    public func resizeToFitWidth() {
        let currentHeight = self.height
        self.sizeToFit()
        self.height = currentHeight
    }
    
    //调整这个视图，以适应其高度
    public func resizeToFitHeight() {
        let currentWidth = self.width
        self.sizeToFit()
        self.width = currentWidth
    }
    
    //getter和setter用于视图的框架原点的x坐标。
    public var x: CGFloat {
        get{
            return self.frame.origin.x
        }
        set (value) {
            self.frame = CGRect(x: value, y: self.y, width: self.width, height: self.height)
        }
    }
    
    //getter和setter用于视图的框架原点的y坐标。
    public var y: CGFloat {
        get {
            return self.frame.origin.y
        }
        set(value) {
            self.frame = CGRect(x: self.x, y: value, width: self.width, height: self.height)
        }
    }

    //获取视图的宽度
    public var width: CGFloat {
        get {
            return self.frame.size.width
        }
        set(value) {
            self.frame = CGRect(x: self.x, y: self.y, width: value, height: self.height)
        }
    }

    //获取视图的高度
    public var height: CGFloat {
        get {
            return self.frame.size.height
        }
        set(value) {
             self.frame = CGRect(x: self.x, y: self.y, width: self.width, height: value)
        }
    }
    
    //getter和setter作为视图最左边的x坐标
    public var left: CGFloat {
        get {
            return self.x
        }
        set(value) {
            self.x = value
        }
    }
    
    //getter和setter作为视图最右边的x坐标
    public var right: CGFloat {
        get {
            return self.x + self.width
        }
        set(value) {
            self.x = value - self.width
        }
    }
    
    //getter和setter作为视图最顶部边的y坐标
    public var top: CGFloat {
        get {
            return self.y
        }
        set(value) {
            self.y = value
        }
    }
    
    //getter和setter作为视图底部最边缘的y坐标
    public var bottom: CGFloat {
        get {
            return self.y + self.height
        } set(value) {
            self.y = value - self.height
        }
    }
    
    //getter和setter视图的frame原点
    public var origin: CGPoint {
        get {
            return self.frame.origin
        } set(value) {
            self.frame = CGRect(origin: value, size: self.frame.size)
        }
    }
    
    //getter和setter作为视图中心的X坐标
    public var centerX: CGFloat {
        get {
            return self.center.x
        } set(value) {
            self.center.x = value
        }
    }
    
    //getter和setter作为视图中心的Y坐标
    public var centerY: CGFloat {
        get {
            return self.center.y
        } set(value) {
            self.center.y = value
        }
    }
    
    //getter和setter为视图大小
    public var size: CGSize {
        get {
            return self.frame.size
        } set(value) {
            self.frame = CGRect(origin: self.frame.origin, size: value)
        }
    }
    
    //左边偏移距离
    public func leftOffset(_ offset: CGFloat) -> CGFloat {
        return self.left - offset
    }
    
    //右边偏移距离
    public func rightOffset(_ offset: CGFloat) -> CGFloat {
        return self.right + offset
    }
    
    //上边偏移距离
    public func topOffset(_ offset: CGFloat) -> CGFloat {
        return self.top - offset
    }
    
    //下边偏移距离
    
    public func bottomOffset(_ offset: CGFloat) -> CGFloat {
        return self.bottom + offset
    }
    
    //将视图横向向右对齐给定的偏移量
    public func alignRight(_ offset: CGFloat) -> CGFloat {
        return self.width - offset
    }
    
    //视图重新排序
    public func reorderSubViews(_ reorder: Bool = false, tagsToIgnore: [Int] = []) -> CGFloat {
        var currentHeight: CGFloat = 0
        for someView in subviews {
            if !tagsToIgnore.contains(someView.tag) && !(someView ).isHidden {
                if reorder {
                    let aView = someView
                    aView.frame = CGRect(x: aView.frame.origin.x, y: currentHeight, width: aView.frame.width, height: aView.frame.height)
                }
                currentHeight += someView.frame.height
            }
        }
        return currentHeight
    }
    
    //移除所有视图
    public func removeSubviews() {
        for subview in subviews {
            subview.removeFromSuperview()
        }
    }
    
    //在超视图中水平居中视图
    public func centerXInSuperView() {
        guard let parentView = superview else {
            assertionFailure("SwiftExtensions Error: The view \(self) doesn't have a superview")
            return
        }
        
        self.x = parentView.width/2 - self.width/2
    }
    
    //在超视图中垂直居中视图
    public func centerYInSuperView() {
        guard let parentView = superview else {
            assertionFailure("SwiftExtensions Error: The view \(self) doesn't have a superview")
            return
        }
        
        self.y = parentView.height/2 - self.height/2
    }
    
    //在超视图中水平和垂直居中视图
    public func centerInSuperView() {
        self.centerXInSuperView()
        self.centerYInSuperView()
    }
    
}

//MARK: 转换扩展


extension UIView {
    public func setRotationX(_ x: CGFloat) {
        var transform = CATransform3DIdentity
        transform.m34 = 1.0 / -1000.0
        transform = CATransform3DRotate(transform, x.degreesToRadians(), 1.0, 0.0, 0.0)
        self.layer.transform = transform
    }
    
    public func setRotationY(_ y: CGFloat) {
        var transform = CATransform3DIdentity
        transform.m34 = 1.0 / -1000.0
        transform = CATransform3DRotate(transform, y.degreesToRadians(), 0.0, 1.0, 0.0)
        self.layer.transform = transform
    }
    
    public func setRotationZ(_ z: CGFloat) {
        var transform = CATransform3DIdentity
        transform.m34 = 1.0 / -1000.0
        transform = CATransform3DRotate(transform, z.degreesToRadians(), 0.0, 0.0, 1.0)
        self.layer.transform = transform
    }
    
    public func setRotation(x: CGFloat, y: CGFloat, z: CGFloat) {
        var transform = CATransform3DIdentity
        transform.m34 = 1.0 / -1000.0
        transform = CATransform3DRotate(transform, x.degreesToRadians(), 1.0, 0.0, 0.0)
        transform = CATransform3DRotate(transform, y.degreesToRadians(), 0.0, 1.0, 0.0)
        transform = CATransform3DRotate(transform, z.degreesToRadians(), 0.0, 0.0, 1.0)
        self.layer.transform = transform
    }
    
    public func setScale(x: CGFloat, y: CGFloat) {
        var transform = CATransform3DIdentity
        transform.m34 = 1.0 / -1000.0
        transform = CATransform3DScale(transform, x, y, 1)
        self.layer.transform = transform
    }
}

//图层扩展
extension UIView {
    public func setCornerRadius(radius: CGFloat) {
        self.layer.cornerRadius = radius
        self.layer.masksToBounds = true
    }
    
    public func addShadow(offset: CGSize, radius: CGFloat, color: UIColor, opacity: Float, cornerRadius: CGFloat? = nil) {
        self.layer.shadowOffset = offset
        self.layer.shadowRadius = radius
        self.layer.shadowOpacity = opacity
        self.layer.shadowColor = color.cgColor
        if let r = cornerRadius {
            self.layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: r).cgPath
        }
    }
    
    public func addBorder(width: CGFloat, color: UIColor) {
        layer.borderWidth = width
        layer.borderColor = color.cgColor
        layer.masksToBounds = true
    }
    
    public func addBorderTop(size: CGFloat, color: UIColor) {
        addBorderUtility(x: 0, y: 0, width: frame.width, height: size, color: color)
    }
    
    public func addBorderTopWithPadding(size: CGFloat, color: UIColor, padding: CGFloat) {
        addBorderUtility(x: padding, y: 0, width: frame.width - padding*2, height: size, color: color)
    }
    
    public func addBorderBottom(size: CGFloat, color: UIColor) {
        addBorderUtility(x: 0, y: frame.height - size, width: frame.width, height: size, color: color)
    }
    
    public func addBorderLeft(size: CGFloat, color: UIColor) {
        addBorderUtility(x: 0, y: 0, width: size, height: frame.height, color: color)
    }
    
    public func addBorderRight(size: CGFloat, color: UIColor) {
        addBorderUtility(x: frame.width - size, y: 0, width: size, height: frame.height, color: color)
    }
    
    fileprivate func addBorderUtility(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, color: UIColor) {
        let border = CALayer()
        border.backgroundColor = color.cgColor
        border.frame = CGRect(x: x, y: y, width: width, height: height)
        layer.addSublayer(border)
    }
    
    public func drawCircle(fillColor: UIColor, strokeColor: UIColor, strokeWidth: CGFloat) {
        let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.width, height: self.width), cornerRadius: self.width/2)
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        shapeLayer.fillColor = fillColor.cgColor
        shapeLayer.strokeColor = strokeColor.cgColor
        shapeLayer.lineWidth = strokeWidth
        self.layer.addSublayer(shapeLayer)
    }
    
    public func drawStroke(width: CGFloat, color: UIColor) {
        let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.width, height: self.width), cornerRadius: self.width/2)
        let shapeLayer = CAShapeLayer ()
        shapeLayer.path = path.cgPath
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = color.cgColor
        shapeLayer.lineWidth = width
        self.layer.addSublayer(shapeLayer)
    }
}

private let UIViewAnimationDuration: TimeInterval = 1
private let UIViewAnimationSpringDamping: CGFloat = 0.5
private let UIViewAnimationSpringVelocity: CGFloat = 0.5

//动画扩展
extension UIView {
    public func spring(animations: @escaping (() -> Void), completion: ((Bool) -> Void)? = nil) {
        spring(duration: UIViewAnimationDuration, animations: animations, completion: completion)
    }
    
    public func spring(duration: TimeInterval, animations: @escaping (() -> Void), completion: ((Bool) -> Void)? = nil) {
        UIView.animate(
            withDuration: UIViewAnimationDuration,
            delay: 0,
            usingSpringWithDamping: UIViewAnimationSpringDamping,
            initialSpringVelocity: UIViewAnimationSpringVelocity,
            options: UIViewAnimationOptions.allowAnimatedContent,
            animations: animations,
            completion: completion
        )
    }
    
    public func animate(duration: TimeInterval, animations: @escaping (() -> Void), completion: ((Bool) -> Void)? = nil) {
        UIView.animate(withDuration: duration, animations: animations, completion: completion)
    }
    
    public func animate(animations: @escaping (() -> Void), completion: ((Bool) -> Void)? = nil) {
        animate(duration: UIViewAnimationDuration, animations: animations, completion: completion)
    }
    
    public func pop() {
        setScale(x: 1.1, y: 1.1)
        spring(duration: 0.2, animations: { [unowned self] () -> Void in
            self.setScale(x: 1, y: 1)
        })
    }
    
    public func popBig() {
        setScale(x: 1.25, y: 1.25)
        spring(duration: 0.2, animations: { [unowned self] () -> Void in
            self.setScale(x: 1, y: 1)
        })
    }
    
    public func reversePop() {
        setScale(x: 0.9, y: 0.9)
        UIView.animate(withDuration: 0.05, delay: 0, options: UIViewAnimationOptions.allowUserInteraction, animations: { [weak self] () -> Void   in
            self?.setScale(x: 1, y: 1)
        })
        
        
    }
    
}

//渲染扩展
extension UIView {
    public func toImage () -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0.0)
        drawHierarchy(in: bounds, afterScreenUpdates: false)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }
}

//手势扩展
extension UIView {
    public func addTapGesture(tapNumber: Int = 1, target: AnyObject, action: Selector) {
        let tap = UITapGestureRecognizer(target: target, action: action)
        tap.numberOfTapsRequired = tapNumber
        addGestureRecognizer(tap)
        isUserInteractionEnabled = true
    }
    
    public func addTapGesture(tapNumber: Int = 1, action: ((UITapGestureRecognizer) -> Void)?) {
        let tap = BlockTap(tapCount: tapNumber, fingerCount: 1, action: action)
        addGestureRecognizer(tap)
        isUserInteractionEnabled = true
    }
    //轻扫
    public func addSwipeGesture(direction: UISwipeGestureRecognizerDirection, numberOfTouches: Int = 1, target: AnyObject, action: Selector) {
        let swipe = UISwipeGestureRecognizer(target: target, action: action)
        swipe.direction = direction
        
        #if os(iOS)
            
            swipe.numberOfTouchesRequired = numberOfTouches
            
        #endif
        
        addGestureRecognizer(swipe)
        isUserInteractionEnabled = true
    }
    
    public func addSwipeGesture(direction: UISwipeGestureRecognizerDirection, numberOfTouches: Int = 1, action: ((UISwipeGestureRecognizer) -> Void)?) {
        let swipe = BlockSwipe(direction: direction, fingerCount: numberOfTouches, action: action)
        addGestureRecognizer(swipe)
        isUserInteractionEnabled = true
    }
    
    public func addPanGesture(target: AnyObject, action: Selector) {
        let pan = UIPanGestureRecognizer(target: target, action: action)
        addGestureRecognizer(pan)
        isUserInteractionEnabled = true
    }
    
    public func addPanGesture(action: ((UIPanGestureRecognizer) -> Void)?) {
        let pan = BlockPan(action: action)
        addGestureRecognizer(pan)
        isUserInteractionEnabled = true
    }
    
    #if os(iOS)
    
    
    public func addPinchGesture(target: AnyObject, action: Selector) {
        let pinch = UIPinchGestureRecognizer(target: target, action: action)
        addGestureRecognizer(pinch)
        isUserInteractionEnabled = true
    }
    
    #endif
    
    #if os(iOS)
    
    
    public func addPinchGesture(action: ((UIPinchGestureRecognizer) -> Void)?) {
        let pinch = BlockPinch(action: action)
        addGestureRecognizer(pinch)
        isUserInteractionEnabled = true
    }
    
    #endif
    
    //
    public func addLongPressGesture(target: AnyObject, action: Selector) {
        let longPress = UILongPressGestureRecognizer(target: target, action: action)
        addGestureRecognizer(longPress)
        isUserInteractionEnabled = true
    }
    
    public func addLongPressGesture(action: ((UILongPressGestureRecognizer) -> Void)?) {
        let longPress = BlockLongPress(action: action)
        addGestureRecognizer(longPress)
        isUserInteractionEnabled = true
    }
    
}

extension UIView {

    public func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask
    }
    

    public func roundView(withBorderColor color: UIColor? = nil, withBorderWidth width: CGFloat? = nil) {
        self.setCornerRadius(radius: min(self.frame.size.height, self.frame.size.width) / 2)
        self.layer.borderWidth = width ?? 0
        self.layer.borderColor = color?.cgColor ?? UIColor.clear.cgColor
    }
    

    public func nakedView() {
        self.layer.mask = nil
        self.layer.borderWidth = 0
    }
}

extension UIView {

    public func shakeViewForTimes(_ times: Int) {
        let anim = CAKeyframeAnimation(keyPath: "transform")
        anim.values = [
            NSValue(caTransform3D: CATransform3DMakeTranslation(-5, 0, 0 )),
            NSValue(caTransform3D: CATransform3DMakeTranslation( 5, 0, 0 ))
        ]
        anim.autoreverses = true
        anim.repeatCount = Float(times)
        anim.duration = 7/100
        
        self.layer.add(anim, forKey: nil)
    }
}

extension UIView {
    //找到顶部的根视图
    func rootView() -> UIView {
        guard let parentView = superview else {
            return self
        }
        return parentView.rootView()
    }
}

private let UIViewDefaultFadeDuration: TimeInterval = 0.4

extension UIView {
    public func fadeIn(_ duration: TimeInterval? = 0.4, delay: TimeInterval? = 0.0, completion: ((Bool) -> Void)? = nil) {
        fadeTo(1.0, duration: duration, delay: delay, completion: completion)
    }
    
    public func fadeTo(_ value: CGFloat, duration: TimeInterval? = 0.4, delay: TimeInterval? = 0.0, completion: ((Bool) -> Void)? = nil) {
        UIView.animate(withDuration: duration ?? UIViewDefaultFadeDuration, delay: delay ?? UIViewDefaultFadeDuration, options: .curveEaseInOut, animations: {
            self.alpha = value
        }, completion: completion)
    }
}
    
extension UIView {
        
        private struct AssociatedKeys {
            static var descriptiveName = "AssociatedKeys.DescriptiveName.blurView"
        }
        
        private (set) var blurView: BlurView {
            get {
                if let blurView = objc_getAssociatedObject(
                    self,
                    &AssociatedKeys.descriptiveName
                    ) as? BlurView {
                    return blurView
                }
                self.blurView = BlurView(to: self)
                return self.blurView
            }
            set(blurView) {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.descriptiveName,
                    blurView,
                    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                )
            }
        }
        
        class BlurView {
            
            private var superview: UIView
            private var blur: UIVisualEffectView?
            private var editing: Bool = false
            private (set) var blurContentView: UIView?
            private (set) var vibrancyContentView: UIView?
            
            var animationDuration: TimeInterval = 0.1
            
            /**
             * Blur style. After it is changed all subviews on
             * blurContentView & vibrancyContentView will be deleted.
             */
            var style: UIBlurEffectStyle = .light {
                didSet {
                    guard oldValue != style,
                        !editing else { return }
                    applyBlurEffect()
                }
            }
            /**
             * Alpha component of view. It can be changed freely.
             */
            var alpha: CGFloat = 0 {
                didSet {
                    guard !editing else { return }
                    if blur == nil {
                        applyBlurEffect()
                    }
                    let alpha = self.alpha
                    UIView.animate(withDuration: animationDuration) {
                        self.blur?.alpha = alpha
                    }
                }
            }
            
            init(to view: UIView) {
                self.superview = view
            }
            
            func setup(style: UIBlurEffectStyle, alpha: CGFloat) -> Self {
                self.editing = true
                
                self.style = style
                self.alpha = alpha
                
                self.editing = false
                
                return self
            }
            
            func enable(isHidden: Bool = false) {
                if blur == nil {
                    applyBlurEffect()
                }
                
                self.blur?.isHidden = isHidden
            }
            
            private func applyBlurEffect() {
                blur?.removeFromSuperview()
                
                applyBlurEffect(
                    style: style,
                    blurAlpha: alpha
                )
            }
            
            private func applyBlurEffect(style: UIBlurEffectStyle,
                                         blurAlpha: CGFloat) {
                superview.backgroundColor = UIColor.clear
                
                let blurEffect = UIBlurEffect(style: style)
                let blurEffectView = UIVisualEffectView(effect: blurEffect)
                
                let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
                let vibrancyView = UIVisualEffectView(effect: vibrancyEffect)
                blurEffectView.contentView.addSubview(vibrancyView)
                
                blurEffectView.alpha = blurAlpha
                
                superview.insertSubview(blurEffectView, at: 0)
                
                blurEffectView.addAlignedConstrains()
                vibrancyView.addAlignedConstrains()
                
                self.blur = blurEffectView
                self.blurContentView = blurEffectView.contentView
                self.vibrancyContentView = vibrancyView.contentView
            }
        }
        
        private func addAlignedConstrains() {
            translatesAutoresizingMaskIntoConstraints = false
            addAlignConstraintToSuperview(attribute: NSLayoutAttribute.top)
            addAlignConstraintToSuperview(attribute: NSLayoutAttribute.leading)
            addAlignConstraintToSuperview(attribute: NSLayoutAttribute.trailing)
            addAlignConstraintToSuperview(attribute: NSLayoutAttribute.bottom)
        }
        
        private func addAlignConstraintToSuperview(attribute: NSLayoutAttribute) {
            superview?.addConstraint(
                NSLayoutConstraint(
                    item: self,
                    attribute: attribute,
                    relatedBy: NSLayoutRelation.equal,
                    toItem: superview,
                    attribute: attribute,
                    multiplier: 1,
                    constant: 0
                )
            )
        }
    }

#endif


